<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>

    <div id="box"></div>


    <script>
        // 1) 以前创建对象 -- 这种创建对象的方式：对象中的属性被访问或被修改 都没法监听到。
        // var obj = {
        //     name: 'zzz'
        // }

        // 2) 所以要把obj对象先定义成一个空对象。再通过Object.defineProperty(obj, '属性') 来给obj对象添加属性。
        // 再添加 get 和 set方法
        var obj = {}

        var obox = document.getElementById('box')

        Object.defineProperty(obj, 'name', { // 给obj对象添加name属性, 任何访问都会走get方法, 任何修改都会走set方法
            get:function () {
                console.log('get')
                return obox.innerHTML // 访问的时候拿到值
            }, 
            set (value) { // ES6中简写
                console.log('set', value) // value就能拦截到修改后的值
                // 3) vue再将拦截到的属性值写入到DOM节点中
                obox.innerHTML = value
            }
        })
        // 此时在控制台直接测试。 (obj.name = 'zzz' 回车 --- 输出 set  zzz)

        // 此时： 我们也封装了一个 通过数据来改变DOM数据的方法。
        // vue中： 当我们把一个普通的JavaScript对象传入Vue实例作为data选项，Vue将遍历此对象所有的property,并使用Object.defineProperty把这些property全部转为 getter/setter
        // Object.defineProperty() 是ES5中一个无法shim的特性,这也就是Vue不支持IE8以及更低版本浏览器的原因

        // 每次data中的数据更改的时候,vue通过setter拦截,通过watcher触发更新,watcher是观察者,它收集了很多跟状态相关的依赖以及它的发布者和订阅者,触发这些订阅者,进行调用，这样组件就能更新了。



        // 总结： Object.defineProperty有以下缺点：
        //  1)无法监听ES6的Set、Map变化
        //  2)无法监听Class类型的数据
        //  3)无法监听属性的新增和删除(例如: data中未定义的变量，之后在方法中给这个变量赋值, 页面中也无法显示这个变量,因为未被监听到。 当然也会通过hack方案来解决这种问题)
        //  1)无法监听数组元素的新增和删除


        // 针对  Object.defineProperty的缺点,ES6 Proxy都能得到完美解决，它唯一的缺点就是对IE不友好，所以vue3在检测到如果是使用IE的情况下,会自动降级为  Object.defineProperty的数据监听系统 (没错：IE11都不支持Proxy)
        // vue3中：无需hack，直接底层支持一切。

    </script>
</body>
</html>